import serial
import time
import threading
import configparser
from typing import Callable, Optional
from .logger_config import get_locker_logger

# 配置日志
logger = get_locker_logger()


class Locker:
    """电磁锁控制类，通过串口与Arduino通信"""
    
    def __init__(self, config_file="config.ini"):
        # 加载配置文件
        self.config = configparser.ConfigParser()
        self.config.read(config_file, encoding='utf-8')
        
        # 从配置文件读取串口参数
        self.port = self.config.get('serial', 'port')
        self.baudrate = self.config.getint('serial', 'baudrate')
        self.timeout = self.config.getint('serial', 'timeout')
        
        # 从配置文件读取电磁锁参数
        self.auto_lock_delay = self.config.getint('locker', 'auto_lock_delay')
        
        # 串口对象
        self.ser = None
        self.connected = False
        
        # 状态回调函数
        self.status_callback: Optional[Callable[[str, str], None]] = None
        
        # 串口读取线程
        self.read_thread = None
        self.running = False
        
        # 锁状态
        self.locked = None
        self.opened = None
        
        # 自动关锁定时器
        self.auto_lock_timer = None
        
    def connect(self):
        """连接串口"""
        try:
            self.ser = serial.Serial(self.port, self.baudrate, timeout=self.timeout)
            self.connected = True
            self.running = True
            
            # 启动串口读取线程
            self.read_thread = threading.Thread(target=self._read_serial, daemon=True)
            self.read_thread.start()
            
            logger.info(f"串口连接成功: {self.port} @ {self.baudrate}")
            while self.locked is None or self.opened is None:
                self.request_status()
                time.sleep(3)
            return True
            
        except Exception as e:
            logger.error(f"串口连接失败: {e}")
            return False
    
    def disconnect(self):
        """断开串口连接"""
        self.running = False
        self.connected = False
        
        # 取消自动关锁定时器
        self._cancel_auto_lock_timer()
        
        if self.ser and self.ser.is_open:
            self.ser.close()
            self.ser = None
            
        logger.info("串口连接已断开")
    
    def set_status_callback(self, callback: Callable[[bool], None]):
        """设置状态回调函数
        callback: 回调函数，参数为 (bool)
        """
        self.status_callback = callback
    
    def _read_serial(self):
        """串口读取线程"""
        while self.running and self.connected:
            try:
                if self.ser and self.ser.in_waiting > 0:
                    line = self.ser.readline().decode('utf-8').strip()
                    if line:
                        self._process_serial_data(line)
                time.sleep(0.01)  # 避免CPU占用过高
            except Exception as e:
                logger.error(f"串口读取错误: {e}")
                self.connected = False
                break
    
    def _process_serial_data(self, data: str):
        """处理从Arduino接收的数据"""
        logger.info(f"收到Arduino数据: {data}")
        try:
            if 'LOCK' == data:
                self.locked = True
            elif 'UNLOCK' == data:
                self.locked = False
            elif 'OPEN' == data:
                self.opened = True
                # 调用状态回调函数
                if self.status_callback:
                    self.status_callback(self.opened)
            elif 'CLOSE' == data:
                self.opened = False
                # 调用状态回调函数
                if self.status_callback:
                    self.status_callback(self.opened)
                # 启动自动关锁定时器
                self._start_auto_lock_timer()
            else:
                logger.error(f"UNKNOWN DATA: {data}")
                
        except Exception as e:
            logger.error(f"处理Arduino数据错误: {e}")
    
    def send_command(self, command: str) -> bool:
        """发送命令到Arduino"""
        if not self.connected or not self.ser:
            logger.error("串口未连接")
            return False
        
        try:
            self.ser.write((command + '\n').encode())
            logger.debug(f"发送命令: {command}")
            return True
            
        except Exception as e:
            logger.error(f"发送命令失败: {e}")
            return False
    
    def unlock_door(self) -> bool:
        """开锁
        返回: True-成功, False-失败
        """
        command = f"UNLOCK"
        success = self.send_command(command)
        
        if success:
            logger.info(f"发送开锁命令成功")
        else:
            logger.error(f"发送开锁命令失败")
            
        return success
    
    def lock_door(self) -> bool:
        """关锁
        返回: True-成功, False-失败
        """
        # 检查门状态，如果门是打开状态则不能关锁
        if self.opened is True:
            logger.warning("门处于打开状态，无法关锁")
            return False
        
        command = f"LOCK"
        success = self.send_command(command)
        
        if success:
            logger.info(f"发送关锁命令成功")
        else:
            logger.error(f"发送关锁命令失败")
            
        return success
    
    def get_door_status(self):
        """获取柜门状态
        """
        return self.opened
    
    def get_lock_status(self):
        """获取锁状态
        """
        return self.locked
    
    def request_status(self) -> bool:
        """请求状态更新
        返回: True-成功, False-失败
        """
        command = "STATUS"
        success = self.send_command(command)
        
        if success:
            logger.info(f"请求状态更新成功")
        else:
            logger.error(f"请求状态更新失败")
        return success
    
    def _start_auto_lock_timer(self):
        """启动自动关锁定时器"""
        # 先检查门和锁的状态
        if self.opened is not False or self.locked is not False:
            return
        
        # 取消之前的定时器
        self._cancel_auto_lock_timer()
        
        # 启动新的定时器
        self.auto_lock_timer = threading.Timer(self.auto_lock_delay, self._auto_lock_callback)
        self.auto_lock_timer.start()
        logger.info(f"启动自动关锁定时器，{self.auto_lock_delay}秒后执行")
    
    def _cancel_auto_lock_timer(self):
        """取消自动关锁定时器"""
        if self.auto_lock_timer:
            self.auto_lock_timer.cancel()
            self.auto_lock_timer = None
            logger.debug("取消自动关锁定时器")
    
    def _auto_lock_callback(self):
        """自动关锁回调函数"""
        # 检查当前状态：门关闭且锁未锁定
        if self.opened is False and self.locked is False:
            logger.info("检测到门关闭且锁未锁定，执行自动关锁")
            self.lock_door()
        else:
            logger.debug(f"自动关锁条件不满足: opened={self.opened}, locked={self.locked}")
    
    def is_connected(self) -> bool:
        """检查串口是否连接"""
        return self.connected and self.ser and self.ser.is_open


# 使用示例
if __name__ == "__main__":
    def status_callback(status: bool):
        """状态回调函数示例"""
        print(f"开门状态变化: {status}")
    
    # 创建Locker实例
    locker = Locker()
    
    # 设置状态回调
    locker.set_status_callback(status_callback)
    
    # 连接串口
    if locker.connect():
        try:
            print("电磁锁控制系统启动")
            print("输入命令:")
            print("  unlock - 开锁（0）")
            print("  lock - 关锁（1）")
            print("  status - 查询状态（2）")
            print("  quit - 退出（q）")
            
            while locker.is_connected():
                command = input("\n> ").strip().split()
                
                if not command:
                    continue
                if command[0] == "quit" or command[0] == "q" or command[0] == "Q":
                    break
                elif command[0] == "unlock" or command[0] == "0":
                    locker.unlock_door()
                elif command[0] == "lock" or command[0] == "1":
                    locker.lock_door()
                elif command[0] == "status" or command[0] == "2":
                    locker.request_status()
                else:
                    print("未知命令")
                    
        except KeyboardInterrupt:
            print("\n用户中断")
        finally:
            locker.disconnect()
    else:
        print("无法连接串口，程序退出")
